package cn.net.shuxing.yifu.common.front.controller;

import cn.net.shuxing.yifu.common.bean.*;
import cn.net.shuxing.yifu.common.constant.CodeConst;
import cn.net.shuxing.yifu.common.constant.DealScene;
import cn.net.shuxing.yifu.common.constant.UserParamConst;
import cn.net.shuxing.yifu.common.constant.UserType;
import cn.net.shuxing.yifu.common.dto.BaseDto;
import cn.net.shuxing.yifu.common.service.*;
import cn.net.shuxing.yifu.common.util.JedisUtil;
import cn.net.shuxing.yifu.common.util.RedisKeyCreator;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Base64Utils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import redis.clients.jedis.Jedis;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;

/**
 * 首页模块Controller
 */
@RestController
@RequestMapping("/front/info")
public class WelcomeController {

    @Autowired
    private FrontCommenController frontCommenController;

    @Autowired
    private ShortService shortService;

    @Autowired
    private ContentAdService contentAdService;

    @Autowired
    private ContentAnService contentAnService;

    @Autowired
    private ContentNewsService contentNewsService;

    @Autowired
    private UserService userService;

    @Autowired
    private UserTransferService userTransferService;

    @Autowired
    private UserRealInfoService userRealInfoService;

    @Autowired
    private CoinTypeService coinTypeService;

    @Autowired
    private FeeService feeService;

    @Autowired
    private FaceVerifyService faceVerifyService;

    @Autowired
    private JedisUtil jedisUtil;

    @Autowired
    private FrontCommonService frontCommonService;

    @Autowired
    private ContentSysService contentSysService;

    @Autowired
    private DealParamService dealParamService;

    @Autowired
    private UserCapitalService userCapitalService;

    /**
     * 获取banner
     *
     * @return
     */
    @ApiOperation(value = "获取banner", httpMethod = "GET")
    @RequestMapping("/banner")
    public BaseDto getBanners() {
        int count = 5;
        List<ContentAd> contentAdList = contentAdService.getByAdState(1);
        if (contentAdList == null)
            return BaseDto.ok(new ArrayList<>(0));
        for (ContentAd contentAd : contentAdList) {
            if (contentAd.getAdPictureUrl() == null)
            {
                contentAd.setAdPicture("");
            }
            else
            {
                contentAd.setAdPicture(contentAd.getAdPictureUrl());
            }
        }
        contentAdList.sort((x,y)->{
            return x.getAdWeight().compareTo(y.getAdWeight());
        });
        BaseDto baseDto = new BaseDto();
        baseDto.setData(contentAdList);
        return baseDto;
    }

    /**
     * 获取置顶公告
     *
     * @return
     */
    @ApiOperation(value = "获取置顶公告", httpMethod = "GET")
    @RequestMapping("/sys/stick")
    public BaseDto getStickContentSys() {
        List<ContentSys> stickContentSys = contentSysService.getStickContentSys();
        BaseDto baseDto = new BaseDto();
        baseDto.setData(stickContentSys);
        return baseDto;
    }

    @RequestMapping("/sys/all")
    public BaseDto getAllSys(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                             @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        List<ContentSys> contentSysList = contentSysService.getAllWithoutComplete();
        PageInfo<ContentSys> pageInfo = new PageInfo<>(contentSysList);
        return BaseDto.ok(pageInfo.getList());
    }

    /**
     * 获取所有单页
     *
     * @param pageNum
     * @param pageSize
     * @return
     */
    @ApiOperation(value = "获取所有单页", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "分页显示的页数", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "分页显示本页显示数据的条数", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/anGetAll")
    public BaseDto getAllAn(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                            @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        BaseDto baseDto = new BaseDto();
        PageHelper.startPage(pageNum, pageSize);
        List<ContentAn> all = contentAnService.getAll();
        for (ContentAn contentAn : all) {
            contentAnService.addSkimNum(contentAn);
        }
        PageInfo<ContentAn> contentAnPageInfo = new PageInfo<>(all);
        baseDto.setData(contentAnPageInfo.getList());
        return baseDto;
    }

    @ApiOperation(value = "单页详细信息", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "anId", value = "单页id", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/anDetai")
    public BaseDto getAn(Integer anId) {
        BaseDto baseDto = new BaseDto();
        baseDto.setData(contentAnService.getByPrimaryKey(anId));
        return baseDto;
    }

    @ApiOperation(value = "获取所有快讯", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "pageNum", value = "分页显示的页数", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "pageSize", value = "分页显示本页显示数据的条数", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/newsGetAll")
    public BaseDto getAllNews(@RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
                              @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
        BaseDto baseDto = new BaseDto();
        PageHelper.startPage(pageNum, pageSize);
        PageInfo<ContentNews> contentNewsPageInfo = new PageInfo<>(contentNewsService.getAll());
        baseDto.setData(contentNewsPageInfo.getList());
        return baseDto;
    }

    @ApiOperation(value = "快讯详细信息", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "newsId", value = "单页id", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/newsDetail")
    public BaseDto getNews(Integer newsId) {
        BaseDto baseDto = new BaseDto();
        baseDto.setData(contentNewsService.getByPrimaryKey(newsId));
        return baseDto;
    }


    /**
     * 获取钱包地址
     *
     * @param userId
     * @return
     */
    @ApiOperation(value = "获取钱包地址", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户id", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/walletAddress")
    public BaseDto generateReceiveCode(Integer userId) {
        if (!userService.checkUser(userId))
            return BaseDto.error("用户不存在");
        int type = userService.getByPrimaryKey(userId).getType();
        BaseDto baseDto = new BaseDto();
        String address = String.valueOf(userId) + "/" + String.valueOf(type);
        address = new String(Base64Utils.encode(address.getBytes()));
        baseDto.setData(address);
        return baseDto;
    }

    /**
     * 获取用户信息
     *
     * @param userIdEncoded 被BASE64编码过的用户id
     * @return
     */
    @ApiOperation(value = "获取用户信息", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userIdEncoded", value = "被BASE64编码过的用户id", required = true, dataType = "String", paramType = "query")
    })
    @RequestMapping("/transfer/userInfo")
    public BaseDto getUserInfo(String userIdEncoded) {
        byte[] decode = Base64Utils.decode(userIdEncoded.getBytes());
        Integer userId = Integer.valueOf(new String(decode));
        Map<String, String> resultMap = new HashMap<>();
        UserRealInfo userRealInfo = userRealInfoService.getByPrimaryKey(userId);
        resultMap.put("realName", userRealInfo.getRealName());
        User user = userService.getByPrimaryKey(userId);
        resultMap.put("username", user.getUsername());
        resultMap.put("userId", userIdEncoded);
        BaseDto baseDto = new BaseDto();
        baseDto.setData(resultMap);
        return baseDto;
    }


    @RequestMapping("/transfer/verify")
    public BaseDto verifyTransfer(int senderId, int receiverId, int receiverType, Integer coinTypeId, BigDecimal count)
    {
        BaseDto capitalPasswordRequired = frontCommenController.isCapitalPasswordRequired(senderId);
        if (capitalPasswordRequired.isError())
            return capitalPasswordRequired;

        User sender = userService.getByPrimaryKey(senderId);
        User receiver = userService.getByPrimaryKey(receiverId);

        Integer senderType = sender.getType();
        if (senderType == UserType.SHAREHOLDER && receiverType == UserType.MEMBER)
        {
            return BaseDto.error("股东不可以直接转账给会员");
        }
        if (senderType == UserType.SHAREHOLDER && receiverType == UserType.NONE)
        {
            BigDecimal activateWalletNeedMinCount = new BigDecimal(dealParamService.getValue(senderId, coinTypeId, UserParamConst.ACTIVATE_WALLET_NEED_MIN_COUNT));
            BigDecimal activateWalletNeedMaxCount = new BigDecimal(dealParamService.getValue(senderId, coinTypeId, UserParamConst.ACTIVATE_WALLET_NEED_MAX_COUNT));

            if (count.compareTo(activateWalletNeedMinCount) < 0)
            {
                BaseDto baseDto = new BaseDto();
                baseDto.setCode(CodeConst.ERROR);
                baseDto.setMsg("转账数量过低,无法激活用户");
                return baseDto;
            }
            if (count.compareTo(activateWalletNeedMaxCount) > 0)
            {
                BaseDto baseDto = new BaseDto();
                baseDto.setCode(CodeConst.ERROR);
                baseDto.setMsg("转账数量过高,无法激活用户");
                return baseDto;
            }


            /** 转账 **/
            UserCapital senderUserCapital = userCapitalService.getByUserIdAndCoinTypeIdAndUserType(senderId, coinTypeId, UserType.SHAREHOLDER);
            BigDecimal aliveCoinCount = senderUserCapital.getAliveCoinCount();
            BigDecimal sleepCoinCount = senderUserCapital.getSleepCoinCount();
            /** 先看股东钱包总额是否足够支付该笔转账 **/
            if (aliveCoinCount.add(sleepCoinCount).compareTo(count) < 0)
                return BaseDto.error("钱包余额不足以支付这笔转账");
            return BaseDto.ok("success");
        }
        else if (senderType == UserType.MEMBER && receiverType == UserType.MEMBER)
        {

            if (senderId == receiverId)
            {
                return BaseDto.error("不允许转给自己");
            }

            /** 允许转账 **/
            Integer type = userService.getByPrimaryKey(senderId).getType();


            if (!frontCommonService.isWalletLeftCountEnough(senderId, coinTypeId, count))
                return BaseDto.error("转账用户钱包余额不足");
            if (!frontCommonService.isWalletLeftCountEnoughMaxKeep(receiverId, coinTypeId, count))
                return BaseDto.error("转账后会导致收账用户钱包余额高于交易钱包最大持有余额,转账失败");

            if (type == UserType.SHAREHOLDER)
            {
                if (!frontCommonService.isWalletLeftCountEnoughMinKeep(senderId, coinTypeId, count))
                    return BaseDto.error("转账后会导致转账用户钱包余额低于交易钱包最小持有余额,转账失败");
            }
            if (type == UserType.MEMBER)
            {
                /** 看坐空 **/
                /** 看是否需要使用坐空 **/
                UserCapital userCapital = userCapitalService.getByUserIdAndCoinTypeId(senderId, coinTypeId);
                if (userCapital == null)
                    return BaseDto.error("钱包里此币种余额为0");
                BigDecimal walletCount = userCapital.getAliveCoinCount();

                /** 获取交易钱包最小活币量 **/
                String dealWalletMinCountStr = dealParamService.getValue(senderId, coinTypeId, UserParamConst.MEMBER_KEEP_ALIVE_COIN_MIN_COUNT);
                BigDecimal dealWalletMinCount = new BigDecimal(dealWalletMinCountStr);

                if ((walletCount.subtract(count)).compareTo(dealWalletMinCount) < 0)
                {
                    Integer userShortCount = shortService.getUserShortCount(senderId, coinTypeId);
                    Integer userShortDeadline = shortService.getUserShortDeadline(senderId, coinTypeId);
                    if (userShortCount <= 0)
                    {
                        if (!frontCommonService.isWalletLeftCountEnoughMinKeep(senderId, coinTypeId, count))
                            return BaseDto.error("转账后会导致转账用户钱包余额低于交易钱包最小持有余额,转账失败");
                    }
                    else
                    {
                        /** 使用坐空 **/
                        if (!shortService.insertShort(senderId, coinTypeId, userShortCount - 1, userShortDeadline))
                        {
                            shortService.updateShort(senderId, coinTypeId, userShortCount - 1, userShortDeadline);
                            Jedis jedis1 = jedisUtil.getJedis();
                            jedis1.set(RedisKeyCreator.shortStartTime(senderId), LocalDateTime.now().toString());
                            jedis1.close();
                        }
                    }
                }

            }
            return BaseDto.ok("success");
        } else if (senderType == UserType.SHAREHOLDER && receiverType == UserType.SHAREHOLDER) {
            if (senderId == receiverId) {
                return BaseDto.error("不允许转给自己");
            }
            /** 允许转账 **/
            if (!frontCommonService.isWalletLeftCountEnough(senderId, coinTypeId, count))
                return BaseDto.error("转账用户钱包余额不足");
            if (!frontCommonService.isWalletLeftCountEnoughMaxKeep(receiverId, coinTypeId, count))
                return BaseDto.error("转账后会导致收账用户钱包余额高于交易钱包最大持有余额,转账失败");
            Integer type = userService.getByPrimaryKey(senderId).getType();
            if (type == UserType.SHAREHOLDER)
            {
                if (!frontCommonService.isWalletLeftCountEnoughMinKeep(senderId, coinTypeId, count))
                    return BaseDto.error("转账后会导致转账用户钱包余额低于交易钱包最小持有余额,转账失败");
            }
            if (type == UserType.MEMBER)
            {
                /** 看坐空 **/
                /** 看是否需要使用坐空 **/
                UserCapital userCapital = userCapitalService.getByUserIdAndCoinTypeId(senderId, coinTypeId);
                if (userCapital == null)
                    return BaseDto.error("钱包里此币种余额为0");
                BigDecimal walletCount = userCapital.getAliveCoinCount();

                /** 获取交易钱包最小活币量 **/
                String dealWalletMinCountStr = dealParamService.getValue(senderId, coinTypeId, UserParamConst.MEMBER_KEEP_ALIVE_COIN_MIN_COUNT);
                BigDecimal dealWalletMinCount = new BigDecimal(dealWalletMinCountStr);

                if ((walletCount.subtract(count)).compareTo(dealWalletMinCount) < 0)
                {
                    Integer userShortCount = shortService.getUserShortCount(senderId, coinTypeId);
                    Integer userShortDeadline = shortService.getUserShortDeadline(senderId, coinTypeId);
                    if (userShortCount <= 0)
                    {
                        if (!frontCommonService.isWalletLeftCountEnoughMinKeep(senderId, coinTypeId, count))
                            return BaseDto.error("转账后会导致转账用户钱包余额低于交易钱包最小持有余额,转账失败");
                    }
                    else
                    {
                        /** 使用坐空 **/
                        if (!shortService.insertShort(senderId, coinTypeId, userShortCount - 1, userShortDeadline))
                        {
                            shortService.updateShort(senderId, coinTypeId, userShortCount - 1, userShortDeadline);
                            Jedis jedis1 = jedisUtil.getJedis();
                            jedis1.set(RedisKeyCreator.shortStartTime(senderId), LocalDateTime.now().toString());
                            jedis1.close();
                        }
                    }
                }

            }
            return BaseDto.ok("success");
        }
        BaseDto baseDto = new BaseDto();
        baseDto.setCode(CodeConst.ERROR);
        baseDto.setMsg("暂不支持此种转账");
        return baseDto;
    }

    /**
     * 转账
     *
     * @param senderId     转账用户id
     * @param receiverId   收钱用户id
     * @param receiverType 收钱用户钱包类型, 1会员,2股东,3商家
     * @param coinTypeId   币种id
     * @param count        转账数量
     * @return
     */
    @ApiOperation(value = "转账操作", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "senderId", value = "转账用户id", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "receiverId", value = "收钱用户id", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "coinTypeId", value = "币种id", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "count", value = "转账数量", required = true, dataType = "double", paramType = "query")
    })
    @RequestMapping("/transfer")
    public BaseDto transfer(int senderId, int receiverId, int receiverType, Integer coinTypeId, BigDecimal count, String transferKey) {

        if (!frontCommonService.verifyTransferKey(senderId, transferKey))
            return BaseDto.error("请先完成人脸识别和资金密码验证");

        User sender = userService.getByPrimaryKey(senderId);
        User receiver = userService.getByPrimaryKey(receiverId);

        Integer senderType = sender.getType();
        if (senderType == UserType.SHAREHOLDER && receiverType == UserType.MEMBER) {
            return BaseDto.error("股东不可以直接转账给会员");
        }
        if (senderType == UserType.SHAREHOLDER && receiverType == UserType.NONE) {
            /** 允许转账 **/
            BaseDto baseDto = userTransferService.activateNewWallet(senderId, receiverId, coinTypeId, count);
            if (baseDto != null && baseDto.getCode() == CodeConst.OK) {
                jedisUtil.del(transferKey);
            }
            return baseDto;
        } else if (senderType == UserType.MEMBER && receiverType == UserType.MEMBER) {
            if (senderId == receiverId) {
                return BaseDto.error("不允许转给自己");
            }
            /** 允许转账 **/
            BaseDto baseDto = userTransferService.transfer(senderId, receiverId, coinTypeId, count, DealScene.MEMBER_TRANSFER_MEMBER);
            if (baseDto.getCode() == CodeConst.OK) {
                jedisUtil.del(transferKey);
            }
            return baseDto;
        } else if (senderType == UserType.SHAREHOLDER && receiverType == UserType.SHAREHOLDER) {
            if (senderId == receiverId) {
                return BaseDto.error("不允许转给自己");
            }else {
                /** 允许转账 **/
                BaseDto baseDto = userTransferService.transfer(senderId, receiverId, coinTypeId, count, DealScene.SHAREHOLDER_TRANSFER_SHAREHOLDER);
                if (baseDto.getCode() == CodeConst.OK) {
                    jedisUtil.del(transferKey);
                }
                return baseDto;
            }

        }
        BaseDto baseDto = new BaseDto();
        baseDto.setCode(CodeConst.ERROR);
        baseDto.setMsg("暂不支持此种转账");
        return baseDto;
    }

    /**
     * 获取所有币种
     *
     * @return
     */
    @ApiOperation(value = "获取所有币种", httpMethod = "GET")
    @RequestMapping("/coin/all")
    public BaseDto getAllCoinType() {
        BaseDto baseDto = new BaseDto();
        List<CoinType> coinTypes = coinTypeService.getAll();
        for (CoinType coinType : coinTypes) {
            coinType.setCoinGain(coinType.getCoinGain().subtract(new BigDecimal(1)).multiply(new BigDecimal(100)));
        }
        baseDto.setData(coinTypes);
        return baseDto;
    }

    /**
     * 获取币种信息
     *
     * @param coinTypeId 币种id
     * @return
     */
    @RequestMapping("/coin")
    public BaseDto getCoinTypeById(Integer coinTypeId) {
        CoinType coinType = coinTypeService.getByPrimaryKey(coinTypeId);
        coinType.setCoinGain(coinType.getCoinGain().subtract(new BigDecimal(1)).multiply(new BigDecimal(100)));
        if (coinType == null)
            return BaseDto.error("该币种不存在");
        return BaseDto.ok(coinType);
    }


    @ApiOperation(value = "获取手续费率", httpMethod = "GET")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "userId", value = "用户id", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "coinTypeId", value = "币种id", required = true, dataType = "Integer", paramType = "query"),
            @ApiImplicitParam(name = "dealScene", value = "交易场景", required = true, dataType = "Integer", paramType = "query"),
    })
    @RequestMapping("/transfer/feeRatio")
    public BaseDto getFeeRatio(Integer userId, Integer coinTypeId, Integer dealScene) {
        Fee fee = feeService.getFee(userId, coinTypeId, dealScene);
        BaseDto baseDto = new BaseDto();
        baseDto.setData(fee);
        return baseDto;
    }


    @ApiOperation(value = "人脸识别", httpMethod = "POST")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "img1", value = "人脸照片,经base64编码后的二进制码", required = true, dataType = "String", paramType = "query"),
            @ApiImplicitParam(name = "userId", value = "用户id", required = true, dataType = "Integer", paramType = "query")
    })
    @RequestMapping("/face/verify")
    public BaseDto faceVerify(String img1, Integer userId) {
        UserRealInfo userRealInfo = userRealInfoService.getPhotosByUserId(userId);

        byte[] idCardFrontPhotoFileContent = userRealInfoService.getFileContent(userRealInfo.getIdCardFrontPhoto());

        boolean verify = faceVerifyService.verify(Base64Utils.encodeToString(idCardFrontPhotoFileContent), img1);
        BaseDto baseDto = new BaseDto();
        if (!verify) {
            baseDto.setCode(CodeConst.ERROR);
            baseDto.setMsg("人脸识别未通过");
        } else {
            baseDto.setData("success");
        }
        return baseDto;
    }
}
